<!DOCTYPE html>
<html>

<head>
  <title> 2048-game </title>
  <meta charset="utf-8" />
  <style media="screen">
    #game {
      display: none;
      position: absolute;
      left: 0px;
      top: 0px;
      right: 0px;
      bottom: 0px;
      background-color: #9DA5C3;
      opacity: 0.5;
      z-index: 1;
    }

    .clear:after {
      content: "";
      display: table;
      clear: both;
    }

    .left {
      float: left;
    }

    .right {
      float: right;
    }

    .scoreShow {
      height: 50px;
      text-align: center;
      line-height: 50px;
    }

    .model {
      text-decoration: none;
      color: white;
      background-color: #bbada0;
      font-size: 36px;
      border-radius: 10px;
    }

    .head {
      width: 480px;
      height: 50px;
      margin: 0 auto;
      font-size: 25px;
    }

    #gridPanel {
      width: 480px;
      height: 480px;
      margin: 0 auto;
      background-color: #bbada0;
      border-radius: 10px;
      position: relative;
      z-index: 1;
    }

    .grid,
    .cell {
      width: 100px;
      height: 100px;
      border-radius: 6px;
    }

    .grid {
      background-color: #ccc0b3;
      float: left;
      margin: 16px 0 0 16px;
    }

    .cell {
      position: absolute;
      font-size: 60px;
      text-align: center;
      line-height: 100px;
      color: #fff;
    }

    .n2 {
      background-color: #eee3da
    }

    .n4 {
      background-color: #ede0c8
    }

    .n8 {
      background-color: #f2b179
    }

    .n16 {
      background-color: #f59563
    }

    .n32 {
      background-color: #f67c5f
    }

    .n64 {
      background-color: #f65e3b
    }

    .n128 {
      background-color: #edcf72
    }

    .n256 {
      background-color: #edcc61
    }

    .n512 {
      background-color: #9c0
    }

    .n1024 {
      background-color: #33b5e5
    }

    .n2048 {
      background-color: #09c
    }

    .n4096 {
      background-color: #a6c
    }

    .n8192 {
      background-color: #93c
    }

    .n2,
    .n4 {
      color: #776e65
    }

    #gameover {
      width: 100%;
      display: none;
      position: fixed;
      left: 50%;
      right: 50%;
      top: 148px;
      width: 220px;
      height: 200px;
      border-radius: 10px;
      background-color: white;
      margin-left: -110px;
      text-align: center;
      z-index: 5;
    }

    #gameover>a {
      display: inline-block;
      width: 170px;
      height: 50px;
      border-radius: 10px;
      text-decoration: none;
      background-color: #9F8D77;
      color: white;
      font-size: 36px;
    }
  </style>
</head>

<body>
  <div id="game">
  </div>
  <div class="head clear">
    <div class="scoreShow left">
      <span>Score:</span>
      <span id="score"></span>
    </div>
    <div class="selction right" onclick="getModel(event)">
      <a href="#" class="model" value="3">3X3</a>
      <a href="#" class="model" value="4">4X4</a>
      <a href="#" class="model" type="button">5X5</a>
      <a href="#" class="model" type="button">6X6</a>
      <!-- <input type="text" id="model"> -->
      <!-- <button type="button" name="button" id="set">设置游戏</button> -->
    </div>
  </div>
  <div id="gridPanel">
  </div>
  <div id="gameover">
    <h1 id="Score"></h1>
    <a href="#" id="again" onclick="obj.gameStart()">Try again</a>
  </div>
  <script type="text/javascript">
    var arr = [];

    function $(id) {
      return document.getElementById(id);
    }

    function C(cls) {
      return document.getElementsByClassName(cls);
    }
    var obj = {
      ROW: 4,
      CELL: 4,
      r: 0,
      c: 0,
      f: 0, //r行  c列  f查找的下一位置
      keyCd: 0,
      score: 0,
      createEle: 0, //是否需要创建元素
      eleFragment: "", //文档片段变量
      //游戏开始
      gameStart: function() {
        obj.init();
        document.onkeydown = function(e) { //自动获得事件对象
          switch (e.keyCode) { //判断按键号
            case 37:
              obj.keyCd = 1;
              obj.moveLeft();
              break;
            case 38:
              obj.keyCd = 2;
              obj.moveUp();
              break;
            case 39:
              obj.keyCd = 1;
              obj.moveRight();
              break;
            case 40:
              obj.keyCd = 2;
              obj.moveDown();
              break;
          }
          $("score").innerHTML = obj.score; //更新分数
        }

      },

      //初始化
      init: function() {
        obj.eleFragment = document.createDocumentFragment();
        for (r = 0; r < obj.ROW; r++) {
          arr.push([]);
          for (c = 0; c < obj.CELL; c++) {
            arr[r][c] = 0;
            if (obj.createEle == 1) {
              obj.create(r, c);
            }
          }
        }
        if (obj.createEle == 1) {
          obj.createEle = 0;
          $("gridPanel").innerHTML = ""; //清空原有的元素
          $("gridPanel").appendChild(obj.eleFragment); //添加元素
        }
        obj.score = 0;
        $("score").innerHTML = obj.score;
        $("game").style.display = "none";
        $("gameover").style.display = "none";
        obj.random(); //开始游戏随机生成两个数
        obj.random();
        obj.updateView();
      },
      //创建div元素，添加到gridPanel中
      create: function(r, c) {
        var grid, cell;
        var increment = 14,
          grWidth, grHeight, grMarginTop, grMarginLeft, ceWidth, ceHight;
        grid = document.createElement("div");
        cell = document.createElement("div");
        grid.id = "g" + r + c;
        grid.className = "grid";
        cell.id = "c" + r + c;
        cell.className = "cell";

        if (obj.ROW == 3) {
          increment = 24;
        } else if (obj.ROW == 4) {
          increment = 18;
        }
        grWidth = grHeight = ceWidth = ceHight = 66 + (6 - obj.ROW) * increment; //优化后
        grMarginTop = grMarginLeft = (480 - grWidth * obj.ROW) / (obj.ROW + 1);
        grid.style.width = grWidth + "px";
        grid.style.height = grHeight + "px";
        grid.style.marginTop = grMarginTop + "px";
        grid.style.marginLeft = grMarginLeft + "px";
        cell.style.width = ceWidth + "px";
        cell.style.height = ceHight + "px";
        cell.style.top = grMarginTop + r * (grMarginTop + ceWidth) + "px";
        cell.style.left = grMarginLeft + c * (grMarginLeft + ceHight) + "px";
        cell.style.lineHeight = ceHight + "px";
        cell.style.fontSize = 30 + (6 - obj.ROW) * 10 + "px";
        //优化前
        /*if (obj.ROW == 3) {
          grid.style.width = "140px";
          grid.style.height = "140px";
          grid.style.margin = "15px 0 0 15px";
          cell.style.width = "140px";
          cell.style.height = "140px";
          cell.style.top = 15 + r * 155 + "px"; //设置距离上一位置的高度
          cell.style.left = 15 + c * 155 + "px"; //设置离左一位置的距离
          cell.style.lineHeight = "140px";
        } else if (obj.ROW == 4) {
          grid.style.width = "100px";
          grid.style.height = "100px";
          grid.style.margin = "16px 0 0 16px";
          cell.style.width = "100px";
          cell.style.height = "100px";
          cell.style.top = 16 + r * 116 + "px";
          cell.style.left = 16 + c * 116 + "px";
          cell.style.lineHeight = "100px";
        } else if (obj.ROW == 5) {
          grid.style.width = "75px";
          grid.style.height = "75px";
          grid.style.margin = "17.5px 0 0 17.5px";
          cell.style.width = "75px";
          cell.style.height = "75px";
          cell.style.top = 17.5 + r * 92.5 + "px";
          cell.style.left = 17.5 + c * 92.5 + "px";
          cell.style.fontSize = "40px";
          cell.style.lineHeight = "75px";
        } else if (obj.ROW == 6) {
          grid.style.width = "66px";
          grid.style.height = "66px";
          grid.style.margin = "12px 0 0 12px";
          cell.style.width = "66px";
          cell.style.height = "66px";
          cell.style.top = 12 + r * 78 + "px";
          cell.style.left = 12 + c * 78 + "px";
          cell.style.fontSize = "30px";
          cell.style.lineHeight = "66px";
        }*/
        obj.eleFragment.appendChild(grid);
        obj.eleFragment.appendChild(cell);
      },
      //随机产生一个新的数
      random: function() {
        while (1) {
          var row = Math.floor(Math.random() * obj.ROW);
          var cell = Math.floor(Math.random() * obj.CELL);
          if (arr[row][cell] == 0) { //判断生成的随机数位置为0才随机生成2或4
            arr[row][cell] = (Math.random() > 0.5) ? 4 : 2;
            break;
          }
        }
        // var row = Math.floor(Math.random() * 4);
        // var cell = Math.floor(Math.random() * 4);
        // if (arr[row][cell] == 0) { //判断生成的随机数位置为0才随机生成2或4
        //   arr[row][cell] = (Math.random() > 0.5) ? 4 : 2;
        //   return;
        // }
        // obj.random();//递归影响执行效率
      },
      //更新页面
      updateView: function() {
        var win = 0;
        for (r = 0; r < obj.ROW; r++) {
          for (c = 0; c < obj.CELL; c++) {
            if (arr[r][c] == 0) { //值为0的不显示
              $("c" + r + c).innerHTML = ""; //0不显示
              $("c" + r + c).className = "cell" //清除样式
            } else {
              $("c" + r + c).innerHTML = arr[r][c];
              $("c" + r + c).className = "cell n" + arr[r][c]; //添加不同数字的颜色
              if (obj.ROW == 3 && arr[r][c] == 1024) {
                win = 1;
              } else if (obj.ROW == 4 && arr[r][c] == 2048) {
                win = 1;
              } else if (obj.ROW == 5 && arr[r][c] == 4096) {
                win = 1;
              } else if (obj.ROW == 6 && arr[r][c] == 8192) {
                win = 1;
              }
            }
          }
        }
        if (win == 1) { //通关
          $("game").style.display = "block";
          $("gameover").style.display = "block";
          $("Score").innerHTML = "You win!<br>Score:" + obj.score;
        }
        if (obj.isGameOver()) { //游戏失败
          $("game").style.display = "block";
          $("gameover").style.display = "block";
          $("Score").innerHTML = "GAME OVER!<br>Score:" + obj.score;
          console.log("gameover");
        }
      },
      //游戏失败
      isGameOver: function() {
        for (r = 0; r < obj.ROW; r++) {
          for (c = 0; c < obj.CELL; c++) {
            if (arr[r][c] == 0) { //有0还不是gameover
              return false;
            } else if (c != obj.CELL - 1 && arr[r][c] == arr[r][c + 1]) { //左往右  前一个和下一个不相等
              return false;
            } else if (r != obj.ROW - 1 && arr[r][c] == arr[r + 1][c]) { //上往下 上一个和下一个不相等
              return false;
            }
          }
        }
        return true;
      },
      //查找下一个不为0的数值的位置
      find: function(r, c, start, condition, direction) {
        if (obj.keyCd == 2) { //上下按键
          if (direction == 1) { //向上按键  f++
            for (var f = start; f < condition; f += direction) {
              if (arr[f][c] != 0) {
                return f;
              }
            }
          } else { //向下按键 f--
            for (var f = start; f >= condition; f += direction) {
              if (arr[f][c] != 0) {
                return f;
              }
            }
          }

        } else { //左右按键
          if (direction == 1) { //左按键   f++
            for (var f = start; f < condition; f += direction) {
              if (arr[r][f] != 0) {
                return f;
              }
            }
          } else { //右按键  f--
            for (var f = start; f >= condition; f += direction) {
              if (arr[r][f] != 0) {
                return f;
              }
            }
          }
        }
        return null; //循环结束仍然没有找到！=0的数值，返回null
      },
      //左按键的处理
      dealToLeft: function(r) {
        var next;
        for (c = 0; c < obj.ROW; c++) {
          next = obj.find(r, c, c + 1, obj.CELL, 1); //找出第一个不为0的位置
          if (next == null) break; //没有找到就返回
          //如果当前位置为0
          if (arr[r][c] == 0) {
            arr[r][c] = arr[r][next]; //把找到的不为0的数值替换为当前位置的值
            arr[r][next] = 0; //找到的位置清0
            c--; //再次循环多一次，查看后面否有值与替换后的值相同，
          } else if (arr[r][c] == arr[r][next]) { //如果当前位置与找到的位置数值相等，则相加
            arr[r][c] *= 2;
            arr[r][next] = 0;
            obj.score += arr[r][c];
          }
        }
      },
      move: function(itertor) {
        var before, //没处理前
          after; //after处理后
        before = arr.toString();
        itertor(); //执行for函数
        after = arr.toString();
        if (before != after) { //前后对比，如果不同就update
          obj.random();
          obj.updateView();
        }
      },
      moveLeft: function() {
        obj.move(function() {
          for (r = 0; r < obj.ROW; r++) {
            obj.dealToLeft(r);
          }
        })
        // if 当前位置 不为零
        // 从当前位置，下一个成员开始，遍历，
        // 如果找到，与当前位置相等的数，
        // 两者相加，并把不为零的成员，设置为零
        // 如果 当前位置是 零
        // 从当前位置下一个成员开始遍历
        // 如果找到 第一个不为零的成员
        // 当前位置数值设置为这个不为零的成员的值 ，并且把那个不为零的成员设置为 0
      },
      //右按键处理
      dealToRight: function(r) {
        var next;
        for (c = obj.CELL - 1; c >= 0; c--) {
          next = obj.find(r, c, c - 1, 0, -1); //找出第一个不为0的位置
          if (next == null) break; //没有找到就返回
          //如果当前位置为0
          if (arr[r][c] == 0) {
            arr[r][c] = arr[r][next]; //把找到的不为0的数值替换为当前位置的值
            arr[r][next] = 0; //找到的位置清0
            c++; //再次循环多一次，查看后面否有值与替换后的值相同，
          } else if (arr[r][c] == arr[r][next]) { //如果当前位置与找到的位置数值相等，则相加
            arr[r][c] *= 2;
            arr[r][next] = 0;
            obj.score += arr[r][c];
          }
        }
      },
      moveRight: function() {
        obj.move(function() {
          for (r = 0; r < obj.ROW; r++) {
            obj.dealToRight(r);
          }
        })
      },
      //上按键处理
      dealToUp: function(c) {
        var next;
        for (r = 0; r < obj.ROW; r++) {
          next = obj.find(r, c, r + 1, obj.ROW, 1); //找出第一个不为0的位置
          if (next == null) break;
          //如果当前位置为0
          if (arr[r][c] == 0) {
            arr[r][c] = arr[next][c]; //把找到的不为0的数值替换为当前位置的值
            arr[next][c] = 0; //找到的位置清0
            r--; //再次循环多一次，查看后面否有值与替换后的值相同
          } else if (arr[r][c] == arr[next][c]) { //如果当前位置与找到的位置数值相等，则相加
            arr[r][c] *= 2;
            arr[next][c] = 0;
            obj.score += arr[r][c];
          }
        }
      },
      moveUp: function() {
        obj.move(function() {
          for (c = 0; c < obj.CELL; c++) {
            obj.dealToUp(c);
          }
        })
      },
      //下按键处理
      dealToDown: function(c) {
        var next;
        for (r = obj.ROW - 1; r >= 0; r--) {
          next = obj.find(r, c, r - 1, 0, -1); //找出第一个不为0的位置
          if (next == null) {
            break;
          }
          //如果当前位置为0
          if (arr[r][c] == 0) {
            arr[r][c] = arr[next][c]; //把找到的不为0的数值替换为当前位置的值
            arr[next][c] = 0; //找到的位置清0
            r++; //再次循环多一次，查看后面否有值与替换后的值相同
          } else if (arr[r][c] == arr[next][c]) { //如果当前位置与找到的位置数值相等，则相加
            arr[r][c] *= 2;
            arr[next][c] = 0;
            obj.score += arr[r][c];
          }
        }
      },
      moveDown: function() {
        obj.move(function() {
          for (c = 0; c < obj.CELL; c++) {
            obj.dealToDown(c);
          }
        })
      }
    }
    window.onload = function() {
      obj.createEle = 1;
      obj.gameStart();
    }
    //切换模式
    function getModel(e) { //事件冒泡获取a元素
      var a = e.target,
        modelValue = 4;
      if (a.nodeName == "A") {
        if (a.innerHTML == "3X3") {
          modelValue = 3;
        } else if (a.innerHTML == "4X4") {
          modelValue = 4;
        } else if (a.innerHTML == "5X5") {
          modelValue = 5;
        } else if (a.innerHTML == "6X6") {
          modelValue = 6;
        }
        obj.ROW = obj.CELL = modelValue;
        obj.createEle = 1; //需要创建格子div元素的标志
        obj.gameStart();
      }
    }

    //   var modelValue = parseInt($("model").value);
    //   if (isNaN(modelValue)) {
    //     modelValue = 4; //默认是4*4
    //   }
    //   if (modelValue <= 2 || modelValue > 6) return; //2格或者大于6格无效
    //   obj.ROW = modelValue;
    //   obj.CELL = modelValue;
    //   obj.createEle = 1;
    //   obj.gameStart();
    //   console.log(modelValue);
    // }
  </script>

</body>

</html>
